home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Packmags
/
Source, The - Issue 5 (1993)(Epsilon)[WB].zip
/
Source, The - Issue 5 (1993)(Epsilon)[WB].adf
/
Source
/
Vectors
/
sirds.lha
/
unsirds.c
< prev
Wrap
C/C++ Source or Header
|
1993-04-12
|
15KB
|
432 lines
/*******************************************************************/
/* */
/* unsirds.c - by Henry Watson - Mar. 30, 1993 */
/* */
/* */
/* This program will take a Single Image Random Dot Stereogram */
/* as an input image and output the 3-D image hidden within it. */
/* Each level of depth in the SIRDS will correspond to a gray */
/* level in the output image (black=far, white=near). */
/* For best results the user should specify the number of gray */
/* levels in the SIRDS image. This value is limited, however, due */
/* to the large amount of memory required to process many depth */
/* levels. */
/* */
/* =============================================================== */
/* */
/* To run, do */
/* % unsirds <input_image> <output_image> [disparity_levels] */
/* */
/*******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <hipl_format.h> /* include HIPS definitions */
#include <math.h>
#define PIXEL_FORMAT PFBYTE /* set the pixel format for the HIPS routines */
typedef byte PIXEL_TYPE; /* set the pixel type for the program to use */
#define NUM_GRAY_LEVELS 256
#define WHITE (PIXEL_TYPE)255
#define BLACK (PIXEL_TYPE)0
#define MAXSIZE 256 /* maximum dimension to image array */
/* and thus input image as well */
#define IMAGE_OFFSET_PCT 0.30 /* stereo image offset in terms of percent */
#define MAXSIRDSWIDTH 332 /* maximum width of final SIRDS image */
/* MAXSIZE * (IMAGE_OFFSET_PCT+1) */
#define DOTHEIGHT 9 /* height of the fusion dots at the page top */
#define MAX_DISP_LEVELS 11 /* maximum number of disparity levels */
#define DISPARITY_LEVELS 11 /* default number of discrete levels of */
/* disparity. Ranges from -d/2 to 0 to +d/2 */
/* (ie. number of levels of depth) */
#define MAX_ITERATIONS 30 /* maximum number of iterations to perform */
/* when trying to get pixels to converge */
#define frame_number 1 /* constant frame number for HIPS routines */
/*******************************************************************/
/* main() */
/* */
/* The sequence of processing steps involves: */
/* - interpreting the command line */
/* - reading the header */
/* - validating the input size, format, etc. */
/* - reading image frame */
/* - performing image processing algorithms */
/* - forming the output image */
/* - writing to file */
/* */
/*******************************************************************/
void main( argc, argv )
int argc;
char **argv;
{
char *input_filename,
*output_filename;
FILE *input_fp, *output_fp;
struct header input_header, output_header;
PIXEL_TYPE Sirds[MAXSIZE+DOTHEIGHT][MAXSIRDSWIDTH],
Object[3][MAX_DISP_LEVELS][MAXSIZE][MAXSIZE];
byte *pixel_ptr;
int rowmax, colmax,
row, col,
changed_flag,
loopcount=1,
right_image_start,
sirdswidth, sirdsheight,
sirdsrowzero,
disparity_levels = DISPARITY_LEVELS,
disparity_offset = -DISPARITY_LEVELS/2,
disparity, displevel,
blackcount, dupecount=0, graylevel;
/* INTERPRETING THE COMMAND LINE */
if( (argc<3) || (argc>4) )
{
printf("Usage: %s <input_image> <output_image> [disparity_levels]\n", argv[0]);
exit(0);
}
input_filename = argv[1]; /* name of input file */
output_filename = argv[2]; /* name of output file */
/* check if optional parameter 'disparity_levels' was specified */
if( argc==4 )
{
disparity_levels = atoi( argv[3] );
disparity_offset = disparity_levels/-2;
/* check the range of the parameter given */
if( (disparity_levels < 2) || (disparity_levels > MAX_DISP_LEVELS) )
{
printf("Invalid number of disparity levels specified.\n");
printf("Value must be in the range: 2 <= disparity_levels <= %d.\n",
MAX_DISP_LEVELS);
printf("Default is %d.\n", DISPARITY_LEVELS);
exit(-1);
}
}
/* READING THE HEADER */
/* open the file and read header */
input_fp = hfopenr( input_filename );
fread_hdr_a( input_fp, &input_header, input_filename );
/* copy image x and y dimensions */
sirdsheight = input_header.orows;
sirdswidth = input_header.ocols;
/* VALIDATING THE INPUT SIZE, FORMAT, ETC. */
if( input_header.pixel_format != PIXEL_FORMAT )
{
printf("This program only handles pixel format %d.\n",PIXEL_FORMAT);
printf("Program aborted.\n");
exit(-1);
}
else if( sirdsheight>MAXSIZE+DOTHEIGHT || sirdswidth>MAXSIRDSWIDTH )
{
printf("Input image too large. Maximum size is %d X %d.\n",
MAXSIZE+DOTHEIGHT,MAXSIRDSWIDTH);
exit(-1);
}
else
{
printf("%d X %d %s is being read.\n",
sirdsheight, sirdswidth, input_filename);
}
/* READING IMAGE FRAME */
/* read the image frame into a buffer; */
/* image is pointed to by input_header.image */
fread_image( input_fp, &input_header, frame_number, input_filename );
/* reformat the buffer into an array */
pixel_ptr = input_header.image;
for( row=0; row < sirdsheight; row++ )
{
pixel_ptr = input_header.image + (row*sirdswidth*input_header.sizepix);
for( col=0; col < sirdswidth; col++ )
Sirds[row][col] = (PIXEL_TYPE) *pixel_ptr++;
}
/* PERFORMING IMAGE PROCESSING ALGORITHM */
/* determine the right stereo image position and the final image size */
sirdsrowzero = DOTHEIGHT;
rowmax = sirdsheight - sirdsrowzero;
colmax = sirdswidth / (IMAGE_OFFSET_PCT+1) + 1;
right_image_start = sirdswidth - colmax;
/* set the object array to all zeros for each disparity level */
for( row=0; row<rowmax; row++ )
for( col=0; col<colmax; col++ )
for( displevel=0; displevel<disparity_levels; displevel++ )
{
Object[0][displevel][row][col] = (PIXEL_TYPE) 0;
}
/* initialize the object array with all possible pixel matches given */
/* the number of disparity levels available. */
printf("Initializing Object array.\n");
for( row=0; row<rowmax; row++ )
{
for( col=0; col<colmax; col++ )
{
/* now check corresponding pixel in right image for a match at */
/* different disparities (ie. different shift posns left or right) */
for( displevel=disparity_offset; displevel<=(-disparity_offset);
displevel++ )
{
/* make sure corresponding position is in range */
if( right_image_start+col+displevel < sirdswidth )
/* see if pixels match... */
if( Sirds[row+DOTHEIGHT][right_image_start+col+displevel]
== Sirds[row+DOTHEIGHT][col] )
{
Object[0][displevel-disparity_offset][row][col] =
(PIXEL_TYPE) 1;
}
}
}
}
/* copy Object[0] to Object[1] to start off... */
for( displevel=0; displevel<disparity_levels; displevel++ )
for( row=0; row < rowmax; row++ )
for( col=0; col < colmax; col++ )
Object[1][displevel][row][col] = Object[0][displevel][row][col];
printf("Converging... \n");
while( loopcount<=MAX_ITERATIONS )
{
int depthpixels[MAX_DISP_LEVELS],
maxpixelsabove, maxpixelsbelow,
i, j, rowpos, colpos, dlevel, vote, oldvalue;
/* reset the changed flag so we can tell when a change has occured. */
/* if a change has not occurred, then we can assume convergence */
changed_flag = 0;
printf("%d\n",loopcount);
for( row=0; row < rowmax; row++ )
for( col=0; col < colmax; col++ )
{
/* calculate number of white pixels in a 3x3 mask on each level */
for( displevel=0; displevel<disparity_levels; displevel++ )
{
/* reset number of pixels counted on this level */
depthpixels[displevel] = 0;
/* count the number of 'on' pixels on this level */
for( i=-1; i<=1; i++ )
for( j=-1; j<=1; j++ )
{
/* new pixel position to check */
rowpos = row+i;
colpos = col+j;
/* make sure pixel is in range and a neighbor (not self) */
if( (rowpos >= 0) && (rowpos < rowmax) &&
(colpos >= 0) && (colpos < colmax) &&
!(i==0 && j==0) )
{
/* if pixel is 'on' then count it */
if( Object[1][displevel][rowpos][colpos]
== (PIXEL_TYPE)1 )
depthpixels[displevel]++;
}
}
}
/* now cycle through disparity levels for this pixel position */
/* and determine if it should be suppressed or re-inforced */
for( displevel=0; displevel<disparity_levels; displevel++ )
{
/* only thin out white ('on') pixels */
if( Object[1][displevel][row][col] == (PIXEL_TYPE) 1 )
{
/* Ok, here's where the customization starts... */
/* Look for the depth levels above and below this one that */
/* have the most pixels 'on' in the masked area. */
maxpixelsabove = 0;
maxpixelsbelow = 0;
for( dlevel=0; dlevel<disparity_levels; dlevel++ )
{
/* update max values when required */
if( depthpixels[dlevel] > maxpixelsabove
&& dlevel > displevel )
{
maxpixelsabove = depthpixels[dlevel];
}
else if( depthpixels[dlevel] > maxpixelsbelow
&& dlevel < displevel )
{
maxpixelsbelow = depthpixels[dlevel];
}
}
/* compute votes from neighbors */
/* neighbors with same disparity re-inforce pixel */
/* neighbors with different disparity suppress pixel */
vote = 2 * depthpixels[displevel] /* re-inforcement */
- maxpixelsabove /* suppression */
- maxpixelsbelow; /* suppression */
/* + Object[0][displevel][row][col] (original value) */
/* save the pixel's old value */
oldvalue = Object[2][displevel][row][col];
/* determine pixel's new value to be on or off */
Object[2][displevel][row][col] = (PIXEL_TYPE)
( (vote >= 1) ? 1 : 0 );
/* set changed flag if there was a change */
if( Object[2][displevel][row][col] != oldvalue )
changed_flag = 1;
}
else
{
/* pixel was off so leave it off */
Object[2][displevel][row][col] = (PIXEL_TYPE) 0;
}
} /* end for loop through each depth level */
} /* end for loop through each pixel */
/* if changed flag not set then it has converged! so break out of loop */
if( !changed_flag )
{
printf("Convergence!\n");
break;
}
/* copy Object[2] to Object[1] to re-iterate... */
for( displevel=0; displevel<disparity_levels; displevel++ )
for( row=0; row < rowmax; row++ )
for( col=0; col < colmax; col++ )
Object[1][displevel][row][col] = Object[2][displevel][row][col];
loopcount++;
} /* end while */
/* FORMING THE OUTPUT IMAGES */
/* initialize a header from scratch and allocate an image for the header */
init_hdr_alloc( &output_header, "", "", frame_number, "", rowmax, colmax,
PIXEL_FORMAT, 1, "" );
/* output_header - address of the HIPS header */
/* "" - original sequence name for documentation purposes */
/* "" - new sequence name for documentation purpose */
/* frame_number - only one frame is required here */
/* "" - date for documentation purposes */
/* rowmax - number of rows */
/* colmax - number of columns */
/* PIXEL_FORMAT - code for pixel format */
/* 1 - number of color planes */
/* "" - the sequence description for documentation purpose */
/* write out image levels to output image with corresponding gray levels */
/* - initialize the output image on the first pass */
/* - produce summary on last pass */
printf("Forming output image.\n");
for( displevel=-1; displevel<=disparity_levels; displevel++ )
{
/* set the pixel_ptr to the image start */
pixel_ptr = output_header.image;
/* set the graylevel according to disparity level */
graylevel = (NUM_GRAY_LEVELS-1) -
(NUM_GRAY_LEVELS-1)/(disparity_levels-1) * (displevel);
if( graylevel == 0 ) graylevel = 1; /* avoid messing up 'blackcount' */
if( displevel == -1 )
{
/* initialize the image to all black */
for( row=0; row < rowmax; row++ )
for( col=0; col < colmax; col++ )
*pixel_ptr++ = (byte) BLACK;
}
else if( displevel == disparity_levels )
{
/* count all black pixels (pixels unaccounted for) */
blackcount =0;
for( row=0; row < rowmax; row++ )
for( col=0; col < colmax; col++ )
if( *pixel_ptr++ == (byte) BLACK )
blackcount++;
printf("Pixels unaccounted for: %d\n",blackcount);
printf("Pixels with multiple gray levels: %d\n\n", dupecount);
}
else
{
/* if pixel at this depth is 'on', then assign the output pixel a */
/* corresponding gray level */
for( row=0; row < rowmax; row++ )
for( col=0; col < colmax; col++ )
if( Object[2][displevel][row][col] == (PIXEL_TYPE) 1 )
{
/* check if pixel is assigned another value */
if( *pixel_ptr != (byte)BLACK )
dupecount++;
/* assign the new pixel value regardless */
*pixel_ptr++ = (byte)graylevel;
}
else
{
/* do nothing, move to next pixel */
pixel_ptr++;
}
}
} /* end for */
/* WRITE TO FILE */
printf("%d X %d %s is being written.\n", rowmax, colmax, output_filename);
output_fp = ffopen( output_filename, "w" );
fwrite_header( output_fp, &output_header, output_filename );
fwrite_image( output_fp, &output_header, 1, output_filename );
fclose( output_fp );
}